//
// Created by Ctzzz on 2024/4/25.
//

#ifndef NDKDEMO_IMAGEDEF_H
#define NDKDEMO_IMAGEDEF_H

#include <malloc.h>
#include <string.h>
#include "stdint.h"
#include "LogUtil.h"

#define IMAGE_FORMAT_RGBA           0x01
#define IMAGE_FORMAT_NV21           0x02
#define IMAGE_FORMAT_NV12           0x03
#define IMAGE_FORMAT_I420           0x04

typedef struct _tag_NativeImage {
    int width;
    int height;
    //
    int format;
    //
    uint8_t *ppPlane[3];

    // 为了方便调试，增加一个成员变量，用于标识当前 NativeImage 是从哪里传递过来的
    _tag_NativeImage() {
        width = 0;
        height = 0;
        format = 0;
        ppPlane[0] = nullptr;
        ppPlane[1] = nullptr;
        ppPlane[2] = nullptr;
    }
} NativeImage;

class NativeImageUtil {
public:

    // 为 NativeImage 分配内存
    static void AllocNativeImage(NativeImage *pImage) {
        // 如果宽高为 0，则直接返回
        if (pImage->width == 0 || pImage->height == 0) {
            LOGCATE("AllocNativeImage pImage width or height is 0");
            return;
        }

        switch (pImage->format) {
            case IMAGE_FORMAT_RGBA:
                // 为 RGBA 格式的图像数据分配内存
                pImage->ppPlane[0] = (uint8_t *) malloc(pImage->width * pImage->height * 4);
                break;
            case IMAGE_FORMAT_NV21:
            case IMAGE_FORMAT_NV12:
                // 为 NV21/NV12 格式的图像数据分配内存
                pImage->ppPlane[0] = (uint8_t *) malloc(pImage->width * pImage->height * 4 / 3);
                pImage->ppPlane[1] = pImage->ppPlane[0] + pImage->width * pImage->height;
                break;
            case IMAGE_FORMAT_I420:
                // 为 I420 格式的图像数据分配内存
                pImage->ppPlane[0] = (uint8_t *) malloc(pImage->width * pImage->height);
                pImage->ppPlane[1] = pImage->ppPlane[0] + pImage->width * pImage->height;
                pImage->ppPlane[2] = pImage->ppPlane[1] + pImage->width * pImage->height / 4;
                break;
            default:
                LOGCATE("NativeImageUtil::AllocNativeImage do not support the format. Format = %d",
                        pImage->format);
                break;
        }
    }

    // 释放 NativeImage 的内存
    static void FreeNativeImage(NativeImage *pImage) {
        if (pImage == nullptr || pImage->ppPlane[0] == nullptr) return;

        if (pImage->ppPlane[0] != nullptr) {
            free(pImage->ppPlane[0]);
            pImage->ppPlane[0] = nullptr;
        }
        if (pImage->ppPlane[1] != nullptr) {
            free(pImage->ppPlane[1]);
            pImage->ppPlane[1] = nullptr;
        }
        if (pImage->ppPlane[2] != nullptr) {
            free(pImage->ppPlane[2]);
            pImage->ppPlane[2] = nullptr;
        }
    }

    // 复制 NativeImage 的数据
    static void CopyNativeImage(NativeImage *pSrcImg, NativeImage *pDstImg) {
        // 如果源图像或目标图像为空，则直接返回
        if (pSrcImg == nullptr || pSrcImg->ppPlane[0] == nullptr) return;

        // 如果源图像和目标图像的格式、宽高不一致，则直接返回
        if (pSrcImg->format != pDstImg->format || pSrcImg->width != pDstImg->width ||
            pSrcImg->height != pDstImg->height) {
            LOGCATE("NativeImageUtil::CopyNativeImage failed, srcImage and dstImage is not the same");
            return;
        }
        // 如果目标图像的内存为空，则为目标图像分配内存
        if (pDstImg->ppPlane[0] == nullptr) {
            AllocNativeImage(pDstImg);
        }

        switch (pSrcImg->format) {
            case IMAGE_FORMAT_RGBA:
                // 由于 RGBA 格式的图像数据是连续存储的，因此可以直接使用 memcpy 进行拷贝,
                // 高度 * 4 是因为 RGBA 每个像素占 4 个字节
                memcpy(pDstImg->ppPlane[0], pSrcImg->ppPlane[0],
                       pSrcImg->width * pSrcImg->height * 4);
                break;
            case IMAGE_FORMAT_NV21:
            case IMAGE_FORMAT_NV12:
            case IMAGE_FORMAT_I420:
                // 由于 NV21、NV12、I420 格式的图像数据是连续存储的，因此可以直接使用 memcpy 进行拷贝,
                // 高度 * 3 / 2 是因为 U、V 分量的高度是 Y 分量的一半
                memcpy(pDstImg->ppPlane[0], pSrcImg->ppPlane[0],
                       pSrcImg->width * pSrcImg->height * 1.5);
                break;
            default:
                LOGCATE("NativeImageUtil::CopyNativeImage do not support the format. Format = %d",
                        pSrcImg->format);
                break;
        }
    }
};


#endif //NDKDEMO_IMAGEDEF_H
